package com.dwy2002.room.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.dwy2002.common.Result;
import com.dwy2002.common.utils.JwtUtil;
import com.dwy2002.common.utils.OssUtils;
import com.dwy2002.common.utils.Validator;
import com.dwy2002.enums.Status;
import com.dwy2002.enums.UniversalStatus;
import com.dwy2002.pojo.dto.rooms.ReserveRoomDTO;
import com.dwy2002.pojo.dto.rooms.RoomImagesDTO;
import com.dwy2002.pojo.dto.rooms.RoomsDTO;
import com.dwy2002.pojo.dto.rooms.RoomsPageDTO;
import com.dwy2002.pojo.po.rooms.Reservations;
import com.dwy2002.pojo.po.rooms.Rooms;
import com.dwy2002.pojo.po.rooms.UnavailableDates;
import com.dwy2002.pojo.po.users.Users;
import com.dwy2002.pojo.vo.rooms.RoomsVO;
import com.dwy2002.room.mapper.RoomsMapper;
import com.dwy2002.room.service.IReservationService;
import com.dwy2002.room.service.IRoomImagesService;
import com.dwy2002.room.service.IRoomsService;
import com.dwy2002.room.service.IUnavailableDateService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.locks.ReentrantLock;

import static com.dwy2002.common.Result.*;
import static com.dwy2002.common.utils.Utils.*;

/**
 * @author 杜伟毅
 * @version 1.0
 * @since 2025/01/25
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class RoomsServiceImpl extends ServiceImpl<RoomsMapper, Rooms> implements IRoomsService {
    private final IRoomImagesService roomImagesService;
    private final IUnavailableDateService unavailableDateService;
    private final IReservationService reservationService;
    private final JwtUtil jwtUtil;
    private final IRoomImagesService imagesService;
    private final OssUtils ossUtils;
    private final ReentrantLock lock = new ReentrantLock();


    /**
     * 查询包间的分页信息
     * <p>
     * 查询：可按包间名称搜索
     * <p>
     * 排序：可按包间创建时间、包间修改时间、包间费用进行升序和降序排序，
     * <p>
     * 分类：可按包间状态进行分类。
     *
     * @param roomsPageData RoomsPageDTO 包间类的分页数据类
     * @author 杜伟毅
     * @since 2025/1/25 0025 23:29
     */
    @Override
    public Result<Page<Rooms>> getRoomsPage(RoomsPageDTO roomsPageData) {
        Validator.of(roomsPageData)
                .mustSatisfy(isPageNull(roomsPageData.getPageNo(), roomsPageData.getPageSize()), "请传入分页数据")
                .mustSatisfy(isPageZero(roomsPageData.getPageNo(), roomsPageData.getPageSize()), "分页数据不能为0")
                .validate();

        LambdaQueryWrapper<Rooms> lqw = new LambdaQueryWrapper<>();
        //根据包间名称模糊查询
        lqw.like(!isEmptyOrNull(roomsPageData.getRoomName()), Rooms::getRoomName, roomsPageData.getRoomName())
                //按照包间创建时间排序
                .orderBy(roomsPageData.getCreatedEnabled(), roomsPageData.getCreatedIsAsc(), Rooms::getCreatedAt)
                //按照包间修改时间排序
                .orderBy(roomsPageData.getUpdatedEnabled(), roomsPageData.getUpdatedIsAsc(), Rooms::getUpdatedAt)
                //按照包间费用排序
                .orderBy(roomsPageData.getFeeEnabled(), roomsPageData.getFeeIsAsc(), Rooms::getFee)
                //根据availableFilterEnabled状态,查询某个包间是否可用
                .eq(roomsPageData.getAvailableFilterEnabled(), Rooms::getIsAvailable, roomsPageData.getIsAvailable())
                //根据statusFilterEnabled状态,查询某个某个状态的包间
                .eq(roomsPageData.getStatusFilterEnabled(), Rooms::getStatus, roomsPageData.getStatus());
        //分页
        Page<Rooms> page = new Page<>(roomsPageData.getPageNo(), roomsPageData.getPageSize());
        Page<Rooms> roomsPage = this.page(page, lqw);
        return success(roomsPage);
    }

    /**
     * 创建包间
     *
     * @param rooms RoomsDTO 前端数据
     * @author 杜伟毅
     * @since 2025/1/25 0025 23:35
     */
    @Override
    public Result<Void> insertRooms(RoomsDTO rooms) {
        Validator.of(rooms)
                .notEmpty(RoomsDTO::getRoomName, "包间名称不能为空")
                .notNull(RoomsDTO::getRoomType, "包间类型不能为空")
                .inRange(RoomsDTO::getRoomType, 2, 0, "没有这个包间类型")
                .minValue(RoomsDTO::getSeatingCapacity, 0, "容纳人数不能小于等于0或为空")
                .notZeroDecimal(RoomsDTO::getFee, "价格不能为0或空!")
                .notNull(RoomsDTO::getStatus, "包间状态不能为空")
                .inRange(RoomsDTO::getStatus, 2, 0, "没有这个包间状态")
                .notNull(RoomsDTO::getIsAvailable, "请选择包间是否可用")
                .mustSatisfy(ObjectUtils.isEmpty(rooms.getRoomImages()) && rooms.getRoomImages().size() > 5, "图片数量不能超过5张")
                .validate();
        String roomId = IdWorker.get32UUID();
        Rooms room = BeanUtil.copyProperties(rooms, Rooms.class);
        room.setId(roomId);
        boolean save = save(room);

        saveRoomImage(rooms.getRoomImages(), roomId);

        return saveResult(save, "包间创建成功", "包间创建失败");
    }

    /**
     * 批量删除包间
     *
     * @param ids 包间id
     * @author 杜伟毅
     * @since 2025/2/8 0008 0:35
     */
    @Override
    public Result<Void> deleteListRooms(List<String> ids) {
        if (ids.isEmpty()) {
            return fail(Status.BAD_REQUEST, "id不能为空");
        }

        List<Rooms> rooms = list(new LambdaQueryWrapper<Rooms>().in(Rooms::getId, ids));
        if (isListEmpty(rooms)) {
            return Result.fail(Status.NOT_FOUND, "未找到可删除的包间记录");
        }
        //验证是否是有效id
        List<String> validaId = rooms.stream()
                .map(Rooms::getId)
                .toList();

        //删除封面图片
        rooms.stream()
                .map(Rooms::getImage)  // 提取图像信息
                .forEach(ossUtils::deleteImage); // 删除图像

        //删除数据库里的包间图片链接
        imagesService.deleteBathImage(validaId);

        boolean remove = removeByIds(validaId);
        return handleResult(remove, Status.BAD_REQUEST, "批量删除成功", "删除失败");
    }

    /**
     * 修改包间
     *
     * @param dto 前端数据
     * @author 杜伟毅
     * @since 2025/1/25 0025 23:42
     */
    @Override
    public Result<Void> updateRooms(RoomsDTO dto) {
        Validator.of(dto)
                .notEmpty(RoomsDTO::getId, "包间ID不能为空")
                .notEmpty(RoomsDTO::getRoomName, "包间名称不能为空")
                .notNull(RoomsDTO::getRoomType, "包间类型不能为空")
                .inRange(RoomsDTO::getRoomType, 2, 0, "请输入正确的类型")
                .minValue(RoomsDTO::getSeatingCapacity, 0, "请输入大于0的数")
                .notNull(RoomsDTO::getFee, "价格不能为空")
                .notZeroDecimal(RoomsDTO::getFee, "价格不能小于等于0")
                .notNull(RoomsDTO::getStatus, "状态不能为0")
                .inRange(RoomsDTO::getStatus, 2, 0, "没有这个状态")
                .mustSatisfy(ObjectUtils.isEmpty(dto.getRoomImages()) && dto.getRoomImages().size() > 5, "图片数量不能超过5张")
                .validate();

        Rooms rooms = getOne(new LambdaQueryWrapper<Rooms>().eq(Rooms::getId, dto.getId()));
        if (ObjectUtils.isEmpty(rooms)) return fail(Status.BAD_REQUEST, "包间不存在");

        LambdaUpdateWrapper<Rooms> luw = new LambdaUpdateWrapper<>();
        luw.eq(Rooms::getId, dto.getId())
                .set(Rooms::getRoomName, dto.getRoomName())
                .set(!Objects.equals(rooms.getRoomType(), dto.getRoomType()), Rooms::getRoomType, dto.getRoomType())
                .set(!StringUtils.equals(rooms.getDescription(), dto.getDescription()), Rooms::getDescription, dto.getDescription())
                .set(!Objects.equals(rooms.getSeatingCapacity(), dto.getSeatingCapacity()), Rooms::getSeatingCapacity, dto.getSeatingCapacity())
                .set(!Objects.equals(rooms.getFee(), dto.getFee()), Rooms::getFee, dto.getFee())
                .set(!Objects.equals(rooms.getStatus(), dto.getStatus()), Rooms::getStatus, dto.getStatus())
                .set(!Objects.equals(rooms.getIsAvailable(), dto.getIsAvailable()), Rooms::getIsAvailable, dto.getIsAvailable())
                .set(!StringUtils.equals(rooms.getImage(), dto.getImage()), Rooms::getImage, dto.getImage());
        boolean update = update(luw);

        //保存图片
        saveRoomImage(dto.getRoomImages(), dto.getId());

        // 更安全的删除旧封面图片逻辑
        if (!StringUtils.equals(rooms.getImage(), dto.getImage())
                && !StringUtils.isEmpty(rooms.getImage())) {
            try {
                // 确认新图片已存在再删除旧图片
                if (ossUtils.isImageExist(dto.getImage())) {
                    ossUtils.deleteImage(rooms.getImage());
                }
            } catch (Exception e) {
                log.error("删除旧封面图片失败: {}", rooms.getImage(), e);
            }
        }

        return handleResult(update, "修改成功", "修改失败");
    }

    /**
     * 获取包间详情
     *
     * @param id 包间id
     * @author 杜伟毅
     * @since 2025/2/11 0011 22:50
     */
    @Override
    public Result<RoomsVO> getRoomDetail(String id) {
        if (isEmptyOrNull(id)) {
            return fail(Status.BAD_REQUEST, "包间id不能为空");
        }
        Rooms rooms = getById(id);
        if (ObjectUtils.isEmpty(rooms)) fail(Status.BAD_REQUEST, "包间不存在");
        RoomsVO roomsVO = BeanUtil.copyProperties(rooms, RoomsVO.class);
        roomsVO.setRoomImages(roomImagesService.getRoomImages(id));
        roomsVO.setUnavailableDates(unavailableDateService.getUnavailableDate(id));
        return success(roomsVO);
    }

    /**
     * 预约包间
     *
     * @param dto 预约包间信息
     * @author 杜伟毅
     * @since 2025/2/12 0012 15:33
     */
    @Override
    public Result<Void> reserveRoom(ReserveRoomDTO dto) {
        Rooms room = getById(dto.getRoomId());

        Validator.of(dto)
                .mustSatisfy(ObjectUtils.isEmpty(room), "包间不存在")
                .mustSatisfy(isEmptyOrNull(dto.getRoomId()), "包间id不能为空")
                .mustSatisfy(isListEmpty(dto.getDates()), "预约日期不能为空")
                .mustSatisfy(!room.getIsAvailable(), "当前包间不可用，请另选其他的包间")
                .mustSatisfy(!unavailableDateService.isRoomAvailable(dto.getRoomId(), dto.getDates()), "当前包间的日期不可用，请另选其他的日期")
                .mustSatisfy(reservationService.isUserDuplicateReserve(dto.getRoomId(), dto.getDates()), "您已预约当前包间的日期，不能重复预约，请另选其他的日期")
                .validate();

        //支付逻辑暂空
        /*

         */

        //插入预约信息---Reservation
        lock.lock();
        try {
            Boolean save = saveReservationAndUnavailableDate(dto.getRoomId(), dto.getDates());
            return saveResult(save, "预约成功", "预约失败");
        } finally {
            lock.unlock();
        }
    }

    /**
     * 取消预约包间
     *
     * @param dto 预约包间信息
     * @author 杜伟毅
     * @since 2025/2/12 0012 15:33
     */
    @Override
    public Result<Void> cancelRoomReserve(ReserveRoomDTO dto) {
        Validator.of(dto)
                .mustSatisfy(isEmptyOrNull(dto.getRoomId()), "包间id不能为空")
                .mustSatisfy(isListEmpty(dto.getDates()), "预约日期不能为空")
                .mustSatisfy(isListEmpty(dto.getDates()), "预约日期不能为空")
                .mustSatisfy(!unavailableDateService.isRoomAvailable(dto.getRoomId(), dto.getDates()), "当前包间的没有这个日期，请另选其他的日期")
                .validate();

        //取消支付逻辑和取消订单逻辑暂空
        /*

         */
        //退款逻辑

        //
//        refundsService.recordRefundInfo()

        boolean remove = removeReservationAndUnavailableDate(dto.getRoomId(), dto.getDates());

        return handleResult(remove, "取消预约成功", "取消预约失败");

    }

    //---------------------------------------------------------------------------------------------


    /**
     * 提取方法：保存方法
     *
     * @param images 包间图片集合
     * @param roomId 包间id
     * @author 杜伟毅
     * @since 2025/3/1 0001 1:01
     */
    private void saveRoomImage(List<RoomImagesDTO> images, String roomId) {
        for (RoomImagesDTO image : images) {
            image.setRoomId(roomId);
            if (!imagesService.saveRoomImage(image)) {
                continue;
            }
        }
    }

    /**
     * 如果已支付则插入预约信息和已预约的日期
     *
     * @param id    包间id
     * @param dates 预约的日期集合
     * @return true:插入成功，false：插入失败
     * @author 杜伟毅
     * @since 2025/2/12 0012 23:40
     */
    private Boolean saveReservationAndUnavailableDate(String id, List<LocalDateTime> dates) {
        boolean Rsave = false, Usave = false;
        for (LocalDateTime date : dates) {
            Reservations reservations = new Reservations()
                    .setRoomId(id)
                    .setUserId(jwtUtil.parseToken(getToken(), Users.class).getId())
                    .setReservationDate(date)
                    .setStatus(UniversalStatus.TWO.getNum())
                    .setPaymentStatus(UniversalStatus.TWO.getNum());
            Rsave = Db.save(reservations);
//      将已预约得日期插入--UnavailableDate
            UnavailableDates unavailableDates = new UnavailableDates()
                    .setRoomId(id)
                    .setUnavailableDate(date);
            Usave = Db.save(unavailableDates);
        }
        return Rsave && Usave;
    }

    /**
     * 如果已退款则删除预约信息和已预约的日期
     *
     * @param id    包间id
     * @param dates 预约的日期集合
     * @return true:删除成功，false：删除失败
     * @author 杜伟毅
     * @since 2025/2/14 0014 16:59
     */
    private boolean removeReservationAndUnavailableDate(String id, List<LocalDateTime> dates) {
        boolean Rremove = false, Uremove = false;
        for (LocalDateTime date : dates) {
            Rremove = reservationService.removeReservation(id, date);
            //将已预约得日期删除--UnavailableDate
            Uremove = unavailableDateService.removeUnavailableDate(id, date);
        }
        return Rremove && Uremove;
    }
}
